#include <stdio.h>
#include <sys/time.h>
#include <sched.h>
#include <stdlib.h>
#include <signal.h>
#include <fcntl.h>
#include <error.h>
#include <stdint.h>
#include <pthread.h>
#include <unistd.h>          // 系统调用相关的函数 close()
#include <string.h>          // strcpy, memset(), and memcpy()
#include <sys/types.h>       // 包含了一些基本的系统数据类型 uint8_t、uint16_t 和 uint32_t
#include <sys/socket.h>      // 与套接字相关的函数和数据结构
#include <netinet/in.h>      // 与 Internet 协议族相关的数据结构
#include <netinet/ip.h>      // IP 协议头部的数据结构
#include <netinet/ip_icmp.h> // 定义了 ICMP 协议头部的数据结构
#include <arpa/inet.h>       // 定义了一些 IP 地址转换函数
#include <sys/ioctl.h>       // 进行输入/输出控制的函数和相关宏
#include <bits/ioctls.h>     // 用于 ioctl() 函数的参数
#include <net/if.h>          // 处理网络接口相关的函数和数据结构
#include <linux/if_ether.h>  // 帧格式 以太网帧的一些常量
#include <linux/if_packet.h> // 用于与套接字相关联的网络接口的数据结构 struct sockaddr_ll
#include <net/ethernet.h>    // 以太网帧的数据结构
#include <errno.h>           // errno, perror()
#include <iostream>

#include "../tsmp/tsmp.h"
#include "ptp.h"

#include <string>

#include "../config/writer.h"
#include <sys/ipc.h>
#include <sys/shm.h>
#include <cstring>
#include <cerrno>
#include <atomic>

#define PACKET_LEN 256 // 数据包的最大长度为 2048 字节
#define MAX_PORT_NUM 4
// #define NET_INIT "enp7s0"
extern char *NET_INIT;
extern node_delay_state node;
extern Ptp_Sync ptp_sync;
extern Tunnel *tunnel;
// 用到配置的同步周期和链路延时周期
extern TSNConfig config;
extern int if_master[MAX_PORT_NUM]; // 记录主端口号
extern int if_slave[MAX_PORT_NUM];  // 记录从端口号

uint16_t global_sequence_id_pdelay[MAX_PORT_NUM] = {0X0};
uint16_t global_sequence_id_sync = {0x0};
uint16_t id_pdelay = 0x0;
uint16_t id_sync = 0x0;

uint8_t NEED_RESP = 0x01;
uint8_t NO_NEED_RESP = 0x00;

// 定时器相关结构体
struct sigevent sev;
struct itimerspec its;
struct sigaction sa;

enum SYNC_PDELAY_STATE
{
    SEND_NONE = 0,
    SEND_SYNC,        // 发送完sync
    SEND_PDELAY_RESP, // 发送完pdelay_resp
    SEND_PDELAY_REQ,  // 发送完pdelay_req
};

SYNC_PDELAY_STATE sp_state;

timer_t timerid_pdelay;                   // pdelay的定时器id
timer_t timerid_sync;                     // sync的定时器id
int if_parse_sync_response[MAX_PORT_NUM] = {0}; // 中继节点重新计算cor时需要用

void timer_pdelay(int sig, siginfo_t *info, void *context)
{
    if (id_pdelay % MAX_PORT_NUM == 0)
    {
        id_pdelay += 1;
    }
    send_frame_pdelay(sig, id_pdelay % MAX_PORT_NUM);
    id_pdelay += 1;
}
void send_frame_pdelay(int sig, int port_id) // 到时触发发送程序, sig判断类型，后续两个参数无用
{
    const char *type; // 收到的类型
    int iRet;         // 用来判断是否封装正确
    uint64_t t1, t4;

    switch (sig)
    {
    case 12:
        type = "pdelayreq";
        global_sequence_id_pdelay[port_id] += 1;
        node.port_delay[port_id].local_sequence_id = global_sequence_id_pdelay[port_id]; // 出现段错误

        // printf("pdelay squence id is %u\n", port_delay.local_sequence_id);
        uint8_t *ptp_req;
        ptp_req = sendPdelayReq(node.port_delay[port_id].local_sequence_id, port_id);

        iRet = protect_critical_section(ptp_req, NEED_RESP, type, port_id);
        if (iRet != 0)
        {
            perror("send error-------------------------------------------------------\n");
            break;
        }
        printf("message type is: %s, port id is: %d\n\n", type, port_id);
        sp_state = SYNC_PDELAY_STATE::SEND_PDELAY_REQ; // 下一次响应是对req的响应
        break;
    case 20:
        type = "pdelayresp";
        uint8_t *ptp_resp;
        ptp_resp = sendPdelayResp(port_id);

        iRet = protect_critical_section(ptp_resp, NEED_RESP, type, port_id);
        if (iRet != 0)
        {
            perror("send error-------------------------------------------------------\n");
            break;
        }

        printf("message type: %s\n\n", type);
        sp_state = SYNC_PDELAY_STATE::SEND_PDELAY_RESP; // 下一次响应是对resp的响应

        break;
    case 30:
        type = "pdelayrespfollowup";
        uint8_t *ptp_resp_follow_up;
        ptp_resp_follow_up = sendPdelayRespFollowUp(port_id);

        iRet = protect_critical_section(ptp_resp_follow_up, NO_NEED_RESP, type, port_id);
        if (iRet != 0)
        {
            perror("send error-------------------------------------------------------\n");
            break;
        }
        printf("message type: %s\n\n", type);
        break;
    default:
        break;
    }
    return;
}

void send_frame_sync(int sig, siginfo_t *info, void *context)
{
    const char *type; // 收到的类型
    int iRet;         // 用来判断是否封装正确
    // uint64_t t1, t4;
    switch (sig)
    {
    case 10:
        type = "sync";
        global_sequence_id_sync += 1;
        uint8_t *ptp_sync;
        for (int i = 0; i < MAX_PORT_NUM; i++)
        {
            if (if_master[i] == 1)
            {
                ptp_sync = sendSync(global_sequence_id_sync);
                iRet = protect_critical_section(ptp_sync, NEED_RESP, type, i);
            }
        }
        if (iRet != 0)
        {
            perror("send sync error\n");
            break;
        }
        printf("message type: %s\n\n", type);
        sp_state = SYNC_PDELAY_STATE::SEND_SYNC; // 下一次响应是对sync的响应
        break;
    case 20:
        type = "follow up";
        uint8_t *ptp_follow_up;
        for (int i = 0; i < MAX_PORT_NUM; i++)
        {
            if (if_master[i] == 1)
            {
                ptp_follow_up = sendFollowUp(1, i);
                iRet = protect_critical_section(ptp_follow_up, NO_NEED_RESP, type, i);
            }
        }
        if (iRet != 0)
        {
            perror("send follow up error\n");
            break;
        }
        printf("message type: %s\n\n", type);
        break;
    default:
        break;
    }

    return;
}

int packRec(int gm_flag)
{
    struct Pack_rec tsmp_pack;
    uint64_t t0, t1, t2, t3, t4;
    uint64_t t_sync;
    int sd; // socket句柄
    // 创建套接字
    sd = create_socket_handle(NET_INIT);
    if (sd < 0)
    {
        printf("socket error\n");
    }

    char buf[PACKET_LEN]; // data
    int len, iRet;
    int port_id;
    memset(buf, 0, sizeof(buf)); // 刷新缓冲

    while (1)
    {
        struct Pack_rec *eth = (struct Pack_rec *)buf;
        // 将字符数组 buf 转换为了 struct s_ethernet_header 类型的指针 eth
        // 直接通过 eth 指针来访问以太网帧中的各个字段
        // 接收数据
        struct Init_pack init_pack; // 取ptp
        len = recvfrom(sd, buf, PACKET_LEN, 0, NULL, NULL);

        // 若是收到自己发送的消息，则不进行处理
        const char *str1 = reinterpret_cast<const char *>(init_pack.ptp_header.clock_identify);
        const char *str2 = reinterpret_cast<const char *>(config.port_identity.clockIdentity);
        if (!strcmp(str1, str2) && ntohs(eth->head.type) == 0x12)
        {
            continue;
        }

        if (ntohs(eth->head.ptcl_id) == 0xff01)
        {
            memcpy(&tsmp_pack.head, &eth->head, sizeof(Tsmp_rec_head));          // 打包头
            memcpy(&tsmp_pack.payload, &eth->payload, sizeof(Pack_rec_payload)); // 打包负载

            // 判断接收到的帧是否是响应帧
            if (eth->head.type == 0x11)
            {
                port_id = tsmp_pack.head.source_port;
                printf("---------------port_id:%d\n", port_id);
                memcpy(&init_pack, &tsmp_pack, sizeof(Init_pack));
                if (init_pack.ptp_header.message_type == 0x3 && ntohs(init_pack.ptp_header.sequence_id) == node.port_delay[port_id].ex_sequence_id)
                {
                    t3 = ((uint64_t)ntohl(tsmp_pack.head.local_time_sec)) << 32 | ntohl(tsmp_pack.head.local_time_nanosec);
                    node.port_delay[port_id].timestamp_3_ex = t3;
                    printf("resp response t3=%lx\n\n", node.port_delay[port_id].timestamp_3);
                    send_frame_pdelay(30, port_id); // 发送pdelay_resp_follow_up
                }
                else if (init_pack.ptp_header.message_type == 0x0 && ntohs(init_pack.ptp_header.sequence_id) == ptp_sync.sequence_id)
                {
                    t_sync = ((uint64_t)ntohl(tsmp_pack.head.global_time_sec)) << 32 | ntohl(tsmp_pack.head.global_time_nanosec); // 获取全局时间
                    // 从不同端口转发的sync，sync发送时间存在不同的端口中
                    ptp_sync.t1[port_id] = t_sync;
                    printf("sync response t1=%lx,port_id = %d\n\n", ptp_sync.t1[port_id], port_id);
                    if_parse_sync_response[port_id] = 1;

                    if (config.gm_flag) // 主节点
                    {
                        send_frame_sync(20, NULL, NULL); // 发送followup报文
                    }
                    else
                    {
                        calculate_cor(port_id);
                    }
                }
                else if (init_pack.ptp_header.message_type == 0x2 && ntohs(init_pack.ptp_header.sequence_id) == node.port_delay[port_id].local_sequence_id)
                {
                    t1 = ((uint64_t)ntohl(tsmp_pack.head.local_time_sec)) << 32 | ntohl(tsmp_pack.head.local_time_nanosec); // 获取本地时间
                    printf("req response t1 = %lx\n\n", t1);
                    node.port_delay[port_id].timestamp_1 = t1; // 记录发送pdelay_req的时间
                }
                else
                {
                    printf("这三个类型都不是，收到的类型是：%u, 序列号是：%u\n", init_pack.ptp_header.message_type, ntohs(init_pack.ptp_header.sequence_id));
                }
            }
            else if (eth->head.type == 0x12)
            {
                port_id = tsmp_pack.head.source_port;
                printf("---------------port_id:%d\n", port_id);
                struct Init_pack init_pack; // 取ptp
                memcpy(&init_pack, &tsmp_pack, sizeof(Init_pack));
                uint8_t type = init_pack.ptp_header.message_type;
                printf("type:%u\n", type);
                switch (type)
                {
                case PtpMsgType::E_PDELAY_REQ:                                                                              // 判断接收帧类型，定义在ptp.h里
                    t2 = ((uint64_t)ntohl(tsmp_pack.head.local_time_sec)) << 32 | ntohl(tsmp_pack.head.local_time_nanosec); // 获取t2时间戳
                    node.port_delay[port_id].timestamp_2_ex = t2;
                    printf("t2=%lx\n", node.port_delay[port_id].timestamp_2); // 写入t2
                    iRet = parsePdelayReq(tsmp_pack, port_id);                // 参数为tsmp封装
                    if (iRet == -1)
                    {
                        std::cout << "parse pdelay req error" << std::endl;
                    }
                    printf("req接收到了\n");
                    send_frame_pdelay(20, port_id); // 发送pdelay_resp
                    printf("resp发送出去了\n");

                    break;
                case PtpMsgType::E_PDELAY_RESP:
                    t4 = ((uint64_t)ntohl(tsmp_pack.head.local_time_sec)) << 32 | ntohl(tsmp_pack.head.local_time_nanosec);
                    node.port_delay[port_id].timestamp_4 = t4;
                    // printf("t4=%lx\n", node.port_delay[port_id].timestamp_4);
                    iRet = parsePdelayResp(tsmp_pack, port_id); // 接收pdelay_resp
                    if (iRet == -1)
                    {
                        std::cout << "parse pdelay resp error" << std::endl;
                    }
                    printf("resp接收到了\n");
                    break;
                case PtpMsgType::E_PDELAY_RESP_FOLLOW_UP:
                    iRet = parsePdelayRespFollowUp(tsmp_pack, port_id); // 接收pdelay_resp_follow_up
                    if (iRet == -1)
                    {
                        std::cout << "parse pdelay resp follow up error" << std::endl;
                    }
                    printf("resp follow up接收到了\n");

                    break;
                case PtpMsgType::E_SYNC:        // 判断接收帧类型，定义在ptp.h里
                    if (if_slave[port_id] == 1) // 判断报文是否是从从端口收到报文
                    {
                        t0 = ((uint64_t)ntohl(tsmp_pack.head.global_time_sec)) << 32 | ntohl(tsmp_pack.head.global_time_nanosec);
                        ptp_sync.t0 = t0;
                        iRet = parseSync(tsmp_pack); // 参数为tsmp封装
                        if (iRet == -1)
                        {
                            std::cout << "parse sync error" << std::endl;
                        }
                        ptp_sync.port_id = port_id; // 记录接收sync的端口
                        printf("sync接收到了\n");
                    }
                    else
                    {
                        printf("sync error! it is not from slave port!\n");
                    }
                    break;
                case PtpMsgType::E_FOLLOW_UP: // 判断接收帧类型，定义在ptp.h里
                    if (if_slave[port_id] == 1)
                    {
                        iRet = parseFollowUp(tsmp_pack, port_id); // 参数为tsmp封装
                        if (iRet == -1)
                        {
                            std::cout << "parse follow up error" << std::endl;
                        }
                        printf("follow up接收到了\n");
                    }
                    else
                    {
                        printf("follow up error! it is not from slave port!\n");
                    }
                    break;
                }
            }
        }
        memset(buf, 0, sizeof(buf)); // 刷新缓冲
    }

    // 更新配置：主从端口和定时器
    update_config();

    close(sd);
    return 0;
}

int update_config()
{
    if (tunnel->tag.load(std::memory_order_acquire) == 1)
    {
        printf("---------------------update------------------\n");
        write_TSNConfig(&config, tunnel);
        // 删除pdelay定时器然后重新创建
        if (timer_delete(timerid_pdelay) == -1)
        {
            perror("timer_delete");
            return 1;
        }
        timer_fun_pdelay(1);
        printf("ccccc\n");
        // 删除sync定时器然后重新创建,要先判断该节点是不是主节点，只有主节点才需要更新sync定时器
        if (config.gm_flag)
        {
            if (timer_delete(timerid_sync) == -1)
            {
                perror("timer_delete");
                return 1;
            }
            timer_fun_sync(1);
        }
        for (int i = 0; i <= MAX_PORT_NUM - 1; i++) // 更新主端口和从端口
        {
            if_master[i] = (config.master_port >> i) & 1;
            if_slave[i] = (config.slave_port >> i) & 1;
        }
        // std::cout << "tsnconfig-device: " << config.device_id << '\n';
        tunnel->tag.store(0, std::memory_order_release);
    }
    return 0;
}

// timer_fun函数实现定时器创建和初始化的一些列功能，参数seconds为定时周期，与sync相关的定时器
int timer_fun_sync(int seconds)
{
    struct sigevent sev;
    struct itimerspec its;
    struct sigaction sa;

    // 注册信号处理函数
    sa.sa_flags = SA_SIGINFO;
    sa.sa_sigaction = send_frame_sync; // 指定了信号处理函数

    sigemptyset(&sa.sa_mask);
    if (sigaction(SIGUSR1, &sa, NULL) == -1)
    {
        perror("sigaction");
        return -1;
    }

    // 创建定时器
    sev.sigev_notify = SIGEV_SIGNAL; // 到时间时发送信号
    sev.sigev_signo = SIGUSR1;
    sev.sigev_value.sival_ptr = &timerid_sync;
    if (timer_create(CLOCK_REALTIME, &sev, &timerid_sync) == -1)
    {
        perror("timer_create");
        return -1;
    }

    // 设置定时器的超时时间
    its.it_value.tv_sec = seconds; // seconds秒后触发
    its.it_value.tv_nsec = 0;
    its.it_interval.tv_sec = 0;                         // 触发之后的时间间隔 秒
    its.it_interval.tv_nsec = config.sync_period * 1e6; // 纳秒,配置文件中指定的同步周期
    if (timer_settime(timerid_sync, 0, &its, NULL) == -1)
    {
        perror("timer_settime");
        return -1;
    }

    return 0;
}

// timer_fun函数实现定时器创建和初始化的一些列功能，参数seconds为定时周期，与pdelay相关的定时器
int timer_fun_pdelay(int seconds)
{

    // 注册信号处理函数
    sa.sa_flags = SA_SIGINFO;
    sa.sa_sigaction = timer_pdelay; // 指定了信号处理函数
    sigemptyset(&sa.sa_mask);
    if (sigaction(SIGUSR2, &sa, NULL) == -1)
    {
        perror("sigaction");
        return -1;
    }
    // 创建定时器
    sev.sigev_notify = SIGEV_SIGNAL; // 到时间时发送信号
    sev.sigev_signo = SIGUSR2;
    // timerid_pdelay = new timer_t;
    // sev.sigev_value.sival_ptr = &timerid_pdelay;
    if (timer_create(CLOCK_REALTIME, &sev, &timerid_pdelay) == -1)
    {
        perror("timer_create");
        return -1;
    }
    // 设置定时器的超时时间，启动该定时器
    its.it_value.tv_sec = seconds; // seconds秒后触发
    its.it_value.tv_nsec = 0;
    its.it_interval.tv_sec = 0;
    its.it_interval.tv_nsec = config.link_delay_measure_period * 1e6; // 触发之后的时间间隔
    if (timer_settime(timerid_pdelay, 0, &its, NULL) == -1)
    {
        perror("timer_settime");
        return -1;
    }
    return 0;
}
